#!/usr/bin/env python3
"""
Stripe集成演示应用
实现客户管理、产品管理、订阅管理的完整功能
使用本地文件系统模拟数据库存储
"""

from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, EmailStr
from typing import Optional, Dict, Any, List
import stripe
import json
import os
import uuid
from datetime import datetime
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 初始化FastAPI应用
app = FastAPI(
    title="Stripe集成演示系统",
    description="完整的客户、产品、订阅管理系统",
    version="1.0.0"
)

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 配置Stripe API密钥
stripe.api_key = "sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd"

# 数据存储配置
DATA_DIR = "data"
CUSTOMERS_FILE = os.path.join(DATA_DIR, "customers.json")
PRODUCTS_FILE = os.path.join(DATA_DIR, "products.json")
SUBSCRIPTIONS_FILE = os.path.join(DATA_DIR, "subscriptions.json")

# 确保数据目录存在
os.makedirs(DATA_DIR, exist_ok=True)

# 数据模型定义
class CustomerCreateRequest(BaseModel):
    email: EmailStr
    name: str
    phone: Optional[str] = None
    address: Optional[Dict[str, str]] = None
    metadata: Optional[Dict[str, str]] = None

class CustomerUpdateRequest(BaseModel):
    email: Optional[EmailStr] = None
    name: Optional[str] = None
    phone: Optional[str] = None
    address: Optional[Dict[str, str]] = None
    metadata: Optional[Dict[str, str]] = None

class ProductCreateRequest(BaseModel):
    name: str
    description: Optional[str] = None
    unit_amount: int  # 价格（以分为单位）
    currency: str = "usd"
    interval: str = "month"  # month, year
    interval_count: int = 1
    metadata: Optional[Dict[str, str]] = None

class ProductUpdateRequest(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    metadata: Optional[Dict[str, str]] = None

class SubscriptionCreateRequest(BaseModel):
    customer_id: str
    product_id: str
    payment_behavior: str = "default_incomplete"
    metadata: Optional[Dict[str, str]] = None

class SubscriptionCheckoutRequest(BaseModel):
    customer_id: str
    product_id: str
    success_url: str = "http://localhost:8003/subscription/success?session_id={CHECKOUT_SESSION_ID}"
    cancel_url: str = "http://localhost:8003/subscription/cancel"
    metadata: Optional[Dict[str, str]] = None

class SubscriptionUpdateRequest(BaseModel):
    metadata: Optional[Dict[str, str]] = None

class SubscriptionUpgradeRequest(BaseModel):
    new_product_id: str
    proration_behavior: str = "create_prorations"  # create_prorations, none, always_invoice
    billing_cycle_anchor: str = "now"  # now, unchanged
    metadata: Optional[Dict[str, str]] = None

class CustomerPortalRequest(BaseModel):
    customer_id: str
    return_url: str = "http://localhost:8003/portal-return"

# 数据管理类
class DataStore:
    """本地文件系统数据存储管理器"""
    
    @staticmethod
    def load_data(file_path: str) -> Dict[str, Any]:
        """从JSON文件加载数据"""
        if os.path.exists(file_path):
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except Exception as e:
                logger.error(f"加载数据失败 {file_path}: {e}")
                return {}
        return {}
    
    @staticmethod
    def save_data(file_path: str, data: Dict[str, Any]) -> bool:
        """保存数据到JSON文件"""
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            logger.error(f"保存数据失败 {file_path}: {e}")
            return False

# 客户管理服务
class CustomerService:
    """客户管理服务类"""
    
    def __init__(self):
        self.customers = DataStore.load_data(CUSTOMERS_FILE)
    
    def create_customer(self, request: CustomerCreateRequest) -> Dict[str, Any]:
        """创建新客户"""
        # 检查邮箱是否已存在
        for customer_id, customer_data in self.customers.items():
            if customer_data.get('email') == request.email:
                raise HTTPException(
                    status_code=400, 
                    detail=f"邮箱 {request.email} 已被注册"
                )
        
        try:
            # 在Stripe中创建客户
            stripe_customer = stripe.Customer.create(
                email=request.email,
                name=request.name,
                phone=request.phone,
                address=request.address,
                metadata=request.metadata or {}
            )
            
            # 生成本地客户ID
            local_customer_id = str(uuid.uuid4())
            
            # 构建客户数据
            customer_data = {
                'id': local_customer_id,
                'stripe_customer_id': stripe_customer.id,
                'email': request.email,
                'name': request.name,
                'phone': request.phone,
                'address': request.address,
                'metadata': request.metadata or {},
                'created_at': datetime.now().isoformat(),
                'updated_at': datetime.now().isoformat(),
                'is_active': True
            }
            
            # 保存到本地存储
            self.customers[local_customer_id] = customer_data
            DataStore.save_data(CUSTOMERS_FILE, self.customers)
            
            logger.info(f"客户创建成功: {local_customer_id} - {request.email}")
            return customer_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"创建客户失败: {str(e)}")
            raise HTTPException(status_code=500, detail="创建客户失败")
    
    def get_customer(self, customer_id: str) -> Optional[Dict[str, Any]]:
        """获取客户信息"""
        return self.customers.get(customer_id)
    
    def get_customer_by_email(self, email: str) -> Optional[Dict[str, Any]]:
        """根据邮箱获取客户"""
        for customer_data in self.customers.values():
            if customer_data.get('email') == email:
                return customer_data
        return None
    
    def list_customers(self, limit: int = 100, offset: int = 0) -> List[Dict[str, Any]]:
        """列出客户"""
        customers_list = list(self.customers.values())
        return customers_list[offset:offset + limit]
    
    def update_customer(self, customer_id: str, request: CustomerUpdateRequest) -> Optional[Dict[str, Any]]:
        """更新客户信息"""
        if customer_id not in self.customers:
            return None
        
        customer_data = self.customers[customer_id]
        
        # 检查邮箱是否被其他客户使用
        if request.email and request.email != customer_data.get('email'):
            for cid, cdata in self.customers.items():
                if cid != customer_id and cdata.get('email') == request.email:
                    raise HTTPException(
                        status_code=400, 
                        detail=f"邮箱 {request.email} 已被其他客户使用"
                    )
        
        try:
            # 更新Stripe客户
            update_data = {}
            if request.email:
                update_data['email'] = request.email
            if request.name:
                update_data['name'] = request.name
            if request.phone is not None:
                update_data['phone'] = request.phone
            if request.address is not None:
                update_data['address'] = request.address
            if request.metadata is not None:
                update_data['metadata'] = request.metadata
            
            if update_data:
                stripe.Customer.modify(
                    customer_data['stripe_customer_id'],
                    **update_data
                )
            
            # 更新本地数据
            for key, value in update_data.items():
                customer_data[key] = value
            
            customer_data['updated_at'] = datetime.now().isoformat()
            self.customers[customer_id] = customer_data
            DataStore.save_data(CUSTOMERS_FILE, self.customers)
            
            logger.info(f"客户更新成功: {customer_id}")
            return customer_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"更新客户失败: {str(e)}")
            raise HTTPException(status_code=500, detail="更新客户失败")
    
    def delete_customer(self, customer_id: str) -> bool:
        """删除客户"""
        if customer_id not in self.customers:
            return False
        
        customer_data = self.customers[customer_id]
        
        try:
            # 删除Stripe客户
            stripe.Customer.delete(customer_data['stripe_customer_id'])
            
            # 从本地存储中删除
            del self.customers[customer_id]
            DataStore.save_data(CUSTOMERS_FILE, self.customers)
            
            logger.info(f"客户删除成功: {customer_id}")
            return True
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"删除客户失败: {str(e)}")
            raise HTTPException(status_code=500, detail="删除客户失败")

# 产品管理服务
class ProductService:
    """产品管理服务类"""
    
    def __init__(self):
        self.products = DataStore.load_data(PRODUCTS_FILE)
    
    def create_product(self, request: ProductCreateRequest) -> Dict[str, Any]:
        """创建新产品和价格"""
        # 检查产品名称是否已存在
        for product_id, product_data in self.products.items():
            if product_data.get('name') == request.name:
                raise HTTPException(
                    status_code=400, 
                    detail=f"产品名称 '{request.name}' 已存在"
                )
        
        try:
            # 创建Stripe产品
            stripe_product = stripe.Product.create(
                name=request.name,
                description=request.description,
                metadata=request.metadata or {}
            )
            
            # 创建Stripe价格
            stripe_price = stripe.Price.create(
                product=stripe_product.id,
                unit_amount=request.unit_amount,
                currency=request.currency,
                recurring={
                    "interval": request.interval,
                    "interval_count": request.interval_count
                },
                metadata=request.metadata or {}
            )
            
            # 生成本地产品ID
            local_product_id = str(uuid.uuid4())
            
            # 构建产品数据
            product_data = {
                'id': local_product_id,
                'stripe_product_id': stripe_product.id,
                'stripe_price_id': stripe_price.id,
                'name': request.name,
                'description': request.description,
                'unit_amount': request.unit_amount,
                'currency': request.currency,
                'interval': request.interval,
                'interval_count': request.interval_count,
                'metadata': request.metadata or {},
                'created_at': datetime.now().isoformat(),
                'updated_at': datetime.now().isoformat(),
                'is_active': True
            }
            
            # 保存到本地存储
            self.products[local_product_id] = product_data
            DataStore.save_data(PRODUCTS_FILE, self.products)
            
            logger.info(f"产品创建成功: {local_product_id} - {request.name}")
            return product_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"创建产品失败: {str(e)}")
            raise HTTPException(status_code=500, detail="创建产品失败")
    
    def get_product(self, product_id: str) -> Optional[Dict[str, Any]]:
        """获取产品信息"""
        return self.products.get(product_id)
    
    def list_products(self, limit: int = 100, offset: int = 0) -> List[Dict[str, Any]]:
        """列出产品"""
        products_list = list(self.products.values())
        return products_list[offset:offset + limit]
    
    def update_product(self, product_id: str, request: ProductUpdateRequest) -> Optional[Dict[str, Any]]:
        """更新产品信息"""
        if product_id not in self.products:
            return None
        
        product_data = self.products[product_id]
        
        # 检查产品名称是否被其他产品使用
        if request.name and request.name != product_data.get('name'):
            for pid, pdata in self.products.items():
                if pid != product_id and pdata.get('name') == request.name:
                    raise HTTPException(
                        status_code=400, 
                        detail=f"产品名称 '{request.name}' 已被其他产品使用"
                    )
        
        try:
            # 更新Stripe产品
            update_data = {}
            if request.name:
                update_data['name'] = request.name
            if request.description is not None:
                update_data['description'] = request.description
            if request.metadata is not None:
                update_data['metadata'] = request.metadata
            
            if update_data:
                stripe.Product.modify(
                    product_data['stripe_product_id'],
                    **update_data
                )
            
            # 更新本地数据
            for key, value in update_data.items():
                product_data[key] = value
            
            product_data['updated_at'] = datetime.now().isoformat()
            self.products[product_id] = product_data
            DataStore.save_data(PRODUCTS_FILE, self.products)
            
            logger.info(f"产品更新成功: {product_id}")
            return product_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"更新产品失败: {str(e)}")
            raise HTTPException(status_code=500, detail="更新产品失败")
    
    def delete_product(self, product_id: str) -> bool:
        """删除产品"""
        if product_id not in self.products:
            return False
        
        product_data = self.products[product_id]
        
        try:
            # 删除Stripe价格和产品
            stripe.Price.modify(product_data['stripe_price_id'], active=False)
            stripe.Product.modify(product_data['stripe_product_id'], active=False)
            
            # 从本地存储中删除
            del self.products[product_id]
            DataStore.save_data(PRODUCTS_FILE, self.products)
            
            logger.info(f"产品删除成功: {product_id}")
            return True
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"删除产品失败: {str(e)}")
            raise HTTPException(status_code=500, detail="删除产品失败")

# 订阅管理服务
class SubscriptionService:
    """订阅管理服务类"""
    
    def __init__(self):
        self.subscriptions = DataStore.load_data(SUBSCRIPTIONS_FILE)
        self.customer_service = CustomerService()
        self.product_service = ProductService()
    
    def create_subscription(self, request: SubscriptionCreateRequest) -> Dict[str, Any]:
        """创建订阅"""
        # 重新加载最新数据
        customers_data = DataStore.load_data(CUSTOMERS_FILE)
        products_data = DataStore.load_data(PRODUCTS_FILE)
        
        # 验证客户是否存在
        customer = customers_data.get(request.customer_id)
        if not customer:
            raise HTTPException(status_code=404, detail="客户不存在")
        
        # 验证产品是否存在
        product = products_data.get(request.product_id)
        if not product:
            raise HTTPException(status_code=404, detail="产品不存在")
        
        # 检查是否已有订阅（任何状态）
        for sub_id, sub_data in self.subscriptions.items():
            if (sub_data['customer_id'] == request.customer_id and 
                sub_data['product_id'] == request.product_id):
                if sub_data['status'] == 'active':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已订阅该产品"
                    )
                elif sub_data['status'] in ['incomplete']:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的未付款订阅，请先处理现有订阅"
                    )
                # elif sub_data['status'] == 'canceled':
                #     raise HTTPException(
                #         status_code=400, 
                #         detail="客户已取消过该产品的订阅，如需重新订阅请联系客服"
                #     )
                else:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的订阅记录"
                    )
        
        try:
            # 创建Stripe订阅
            stripe_subscription = stripe.Subscription.create(
                customer=customer['stripe_customer_id'],
                items=[{"price": product['stripe_price_id']}],
                payment_behavior=request.payment_behavior,
                expand=["latest_invoice.payment_intent"],
                metadata=request.metadata or {}
            )
            
            # 生成本地订阅ID
            local_subscription_id = str(uuid.uuid4())
            
            # 构建订阅数据
            subscription_data = {
                'id': local_subscription_id,
                'stripe_subscription_id': stripe_subscription.id,
                'customer_id': request.customer_id,
                'product_id': request.product_id,
                'status': stripe_subscription.status,
                'current_period_start': stripe_subscription.current_period_start,
                'current_period_end': stripe_subscription.current_period_end,
                'cancel_at_period_end': stripe_subscription.cancel_at_period_end,
                'metadata': request.metadata or {},
                'created_at': datetime.now().isoformat(),
                'updated_at': datetime.now().isoformat()
            }
            
            # 保存到本地存储
            self.subscriptions[local_subscription_id] = subscription_data
            DataStore.save_data(SUBSCRIPTIONS_FILE, self.subscriptions)
            
            logger.info(f"订阅创建成功: {local_subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"创建订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="创建订阅失败")

    def create_subscription_checkout(self, request: SubscriptionCheckoutRequest) -> Dict[str, Any]:
        """创建订阅支付会话"""
        # 重新加载最新数据
        customers_data = DataStore.load_data(CUSTOMERS_FILE)
        products_data = DataStore.load_data(PRODUCTS_FILE)
        
        # 验证客户是否存在
        customer = customers_data.get(request.customer_id)
        if not customer:
            raise HTTPException(status_code=404, detail="客户不存在")
        
        # 验证产品是否存在
        product = products_data.get(request.product_id)
        if not product:
            raise HTTPException(status_code=404, detail="产品不存在")
        
        # 检查是否已有订阅（任何状态）
        for sub_id, sub_data in self.subscriptions.items():
            if (sub_data['customer_id'] == request.customer_id and 
                sub_data['product_id'] == request.product_id):
                if sub_data['status'] == 'active':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已订阅该产品"
                    )
                elif sub_data['status'] in ['past_due', 'unpaid']:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的未付款订阅，请先处理现有订阅"
                    )
                elif sub_data['status'] == 'canceled':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已取消过该产品的订阅，如需重新订阅请联系客服"
                    )
                else:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的订阅记录"
                    )
        
        try:
            # 创建Stripe结账会话（订阅模式）
            checkout_session = stripe.checkout.Session.create(
                payment_method_types=["card"],
                line_items=[{
                    "price": product['stripe_price_id'],
                    "quantity": 1,
                }],
                mode="subscription",  # 订阅模式
                success_url=request.success_url,
                cancel_url=request.cancel_url,
                customer=customer['stripe_customer_id'],
                metadata={
                    **(request.metadata or {}),
                    "customer_id": request.customer_id,
                    "product_id": request.product_id,
                    "local_customer_id": request.customer_id,
                    "local_product_id": request.product_id
                }
            )
            
            logger.info(f"订阅支付会话创建成功: {checkout_session.id} 客户: {request.customer_id}")
            return {
                "checkout_url": checkout_session.url,
                "session_id": checkout_session.id,
                "customer_id": request.customer_id,
                "product_id": request.product_id
            }
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"创建订阅支付会话失败: {str(e)}")
            raise HTTPException(status_code=500, detail="创建订阅支付会话失败")
    
    def get_subscription(self, subscription_id: str) -> Optional[Dict[str, Any]]:
        """获取订阅信息"""
        return self.subscriptions.get(subscription_id)
    
    def list_subscriptions(self, limit: int = 100, offset: int = 0) -> List[Dict[str, Any]]:
        """列出所有订阅"""
        subscriptions_list = list(self.subscriptions.values())
        return subscriptions_list[offset:offset + limit]
    
    def get_customer_subscriptions(self, customer_id: str) -> List[Dict[str, Any]]:
        """获取客户的所有订阅"""
        customer_subs = []
        for sub_data in self.subscriptions.values():
            if sub_data['customer_id'] == customer_id:
                # 添加产品和客户信息
                product = self.product_service.get_product(sub_data['product_id'])
                customer = self.customer_service.get_customer(sub_data['customer_id'])
                sub_data_with_details = sub_data.copy()
                sub_data_with_details['product'] = product
                sub_data_with_details['customer'] = customer
                customer_subs.append(sub_data_with_details)
        return customer_subs
    
    def update_subscription(self, subscription_id: str, request: SubscriptionUpdateRequest) -> Optional[Dict[str, Any]]:
        """更新订阅信息"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        try:
            # 更新Stripe订阅
            update_data = {}
            if request.metadata is not None:
                update_data['metadata'] = request.metadata
            
            if update_data:
                stripe.Subscription.modify(
                    subscription_data['stripe_subscription_id'],
                    **update_data
                )
            
            # 更新本地数据
            for key, value in update_data.items():
                subscription_data[key] = value
            
            subscription_data['updated_at'] = datetime.now().isoformat()
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(SUBSCRIPTIONS_FILE, self.subscriptions)
            
            logger.info(f"订阅更新成功: {subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"更新订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="更新订阅失败")
    
    def cancel_subscription(self, subscription_id: str, cancel_at_period_end: bool = True) -> Optional[Dict[str, Any]]:
        """取消订阅"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        try:
            if cancel_at_period_end:
                # 在周期结束时取消
                stripe.Subscription.modify(
                    subscription_data['stripe_subscription_id'],
                    cancel_at_period_end=True
                )
                # 不更新状态,使用webhook更新
                # subscription_data['cancel_at_period_end'] = True
            else:
                # 立即取消
                stripe.Subscription.delete(subscription_data['stripe_subscription_id'])
                # 不更新状态，使用webhook更新
                # subscription_data['status'] = 'canceled'

            subscription_data['updated_at'] = datetime.now().isoformat()
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(SUBSCRIPTIONS_FILE, self.subscriptions)

            logger.info(f"订阅取消成功: {subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"取消订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="取消订阅失败")

    def upgrade_subscription(self, subscription_id: str, request: SubscriptionUpgradeRequest) -> Optional[Dict[str, Any]]:
        """升级/降级订阅（切换产品）"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        # 检查订阅状态，只允许对活跃订阅进行升级/降级
        if subscription_data['status'] != 'active':
            raise HTTPException(
                status_code=400, 
                detail=f"只能对活跃订阅进行升级/降级，当前订阅状态为: {subscription_data['status']}"
            )
        
        # 重新加载最新数据
        products_data = DataStore.load_data(PRODUCTS_FILE)
        
        # 验证新产品是否存在
        new_product = products_data.get(request.new_product_id)
        if not new_product:
            raise HTTPException(status_code=404, detail="新产品不存在")
        
        # 检查是否切换到相同产品
        if subscription_data['product_id'] == request.new_product_id:
            raise HTTPException(status_code=400, detail="不能切换到相同产品")
        
        # 检查客户是否已有新产品的订阅
        for sub_id, sub_data in self.subscriptions.items():
            if (sub_id != subscription_id and 
                sub_data['customer_id'] == subscription_data['customer_id'] and 
                sub_data['product_id'] == request.new_product_id):
                if sub_data['status'] == 'active':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已订阅该产品"
                    )
                elif sub_data['status'] in ['incomplete']:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的未付款订阅，请先处理现有订阅"
                    )
                else:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的订阅记录"
                    )
        
        try:
            # 获取当前订阅的详细信息
            stripe_subscription = stripe.Subscription.retrieve(subscription_data['stripe_subscription_id'])
            
            # 获取当前订阅项目ID
            items = stripe_subscription.items()

            for key, value in items:
                if key == "items":
                    items = value
            # 修改当前subscription对应的产品
            current_subscription_item_id = items.data[0].id
            print(current_subscription_item_id)
            # 设置计费周期锚点
            billing_cycle_anchor = None
            if request.billing_cycle_anchor == "now":
                billing_cycle_anchor = "now"
            elif request.billing_cycle_anchor == "unchanged":
                billing_cycle_anchor = "unchanged"
            
            # 更新Stripe订阅
            updated_subscription = stripe.Subscription.modify(
                subscription_data['stripe_subscription_id'],
                items=[{
                    "id": current_subscription_item_id,
                    "price": new_product['stripe_price_id']
                }],
                proration_behavior=request.proration_behavior,
                billing_cycle_anchor=billing_cycle_anchor,
                expand=["latest_invoice.payment_intent"]
            )
            
            # 更新本地数据
            subscription_data['product_id'] = request.new_product_id
            subscription_data['status'] = updated_subscription.status
            subscription_data['current_period_start'] = updated_subscription.current_period_start
            subscription_data['current_period_end'] = updated_subscription.current_period_end
            subscription_data['updated_at'] = datetime.now().isoformat()
            
            # 更新元数据
            if request.metadata:
                subscription_data['metadata'] = {**(subscription_data.get('metadata', {})), **request.metadata}
            
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(SUBSCRIPTIONS_FILE, self.subscriptions)
            
            logger.info(f"订阅升级/降级成功: {subscription_id} 从产品 {subscription_data['product_id']} 切换到 {request.new_product_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"升级/降级订阅失败: {str(e)}")
            import traceback
            logger.error(f"详细错误信息: {traceback.format_exc()}")
            raise HTTPException(status_code=500, detail=f"升级/降级订阅失败: {str(e)}")

# 初始化服务实例
customer_service = CustomerService()
product_service = ProductService()
subscription_service = SubscriptionService()

# 确保订阅服务使用相同的服务实例
subscription_service.customer_service = customer_service
subscription_service.product_service = product_service

# API路由定义

@app.get("/", response_class=HTMLResponse)
async def read_root():
    """返回主页HTML"""
    try:
        with open("index.html", "r", encoding="utf-8") as f:
            return HTMLResponse(content=f.read())
    except FileNotFoundError:
        return HTMLResponse(content="<h1>Stripe集成演示系统</h1><p>请确保index.html文件存在</p>")

# 客户管理API
@app.post("/api/customers", response_model=Dict[str, Any])
async def create_customer(request: CustomerCreateRequest):
    """创建新客户"""
    return customer_service.create_customer(request)

@app.get("/api/customers", response_model=List[Dict[str, Any]])
async def list_customers(limit: int = 100, offset: int = 0):
    """列出所有客户"""
    return customer_service.list_customers(limit, offset)

@app.get("/api/customers/{customer_id}", response_model=Dict[str, Any])
async def get_customer(customer_id: str):
    """获取客户信息"""
    customer = customer_service.get_customer(customer_id)
    if not customer:
        raise HTTPException(status_code=404, detail="客户不存在")
    return customer

@app.put("/api/customers/{customer_id}", response_model=Dict[str, Any])
async def update_customer(customer_id: str, request: CustomerUpdateRequest):
    """更新客户信息"""
    customer = customer_service.update_customer(customer_id, request)
    if not customer:
        raise HTTPException(status_code=404, detail="客户不存在")
    return customer

@app.delete("/api/customers/{customer_id}")
async def delete_customer(customer_id: str):
    """删除客户"""
    success = customer_service.delete_customer(customer_id)
    if not success:
        raise HTTPException(status_code=404, detail="客户不存在")
    return {"message": "客户删除成功"}

# 产品管理API
@app.post("/api/products", response_model=Dict[str, Any])
async def create_product(request: ProductCreateRequest):
    """创建新产品"""
    return product_service.create_product(request)

@app.get("/api/products", response_model=List[Dict[str, Any]])
async def list_products(limit: int = 100, offset: int = 0):
    """列出所有产品"""
    return product_service.list_products(limit, offset)

@app.get("/api/products/{product_id}", response_model=Dict[str, Any])
async def get_product(product_id: str):
    """获取产品信息"""
    product = product_service.get_product(product_id)
    if not product:
        raise HTTPException(status_code=404, detail="产品不存在")
    return product

@app.put("/api/products/{product_id}", response_model=Dict[str, Any])
async def update_product(product_id: str, request: ProductUpdateRequest):
    """更新产品信息"""
    product = product_service.update_product(product_id, request)
    if not product:
        raise HTTPException(status_code=404, detail="产品不存在")
    return product

@app.delete("/api/products/{product_id}")
async def delete_product(product_id: str):
    """删除产品"""
    success = product_service.delete_product(product_id)
    if not success:
        raise HTTPException(status_code=404, detail="产品不存在")
    return {"message": "产品删除成功"}

# 订阅管理API
@app.post("/api/subscriptions", response_model=Dict[str, Any])
async def create_subscription(request: SubscriptionCreateRequest):
    """创建订阅"""
    return subscription_service.create_subscription(request)

@app.post("/api/subscriptions/checkout", response_model=Dict[str, Any])
async def create_subscription_checkout(request: SubscriptionCheckoutRequest):
    """创建订阅支付会话"""
    return subscription_service.create_subscription_checkout(request)

@app.get("/api/subscriptions", response_model=List[Dict[str, Any]])
async def list_subscriptions(limit: int = 100, offset: int = 0):
    """列出所有订阅"""
    return subscription_service.list_subscriptions(limit, offset)

@app.get("/api/subscriptions/{subscription_id}", response_model=Dict[str, Any])
async def get_subscription(subscription_id: str):
    """获取订阅信息"""
    subscription = subscription_service.get_subscription(subscription_id)
    if not subscription:
        raise HTTPException(status_code=404, detail="订阅不存在")
    return subscription

@app.get("/api/customers/{customer_id}/subscriptions", response_model=List[Dict[str, Any]])
async def get_customer_subscriptions(customer_id: str):
    """获取客户的所有订阅"""
    return subscription_service.get_customer_subscriptions(customer_id)

@app.put("/api/subscriptions/{subscription_id}", response_model=Dict[str, Any])
async def update_subscription(subscription_id: str, request: SubscriptionUpdateRequest):
    """更新订阅信息"""
    subscription = subscription_service.update_subscription(subscription_id, request)
    if not subscription:
        raise HTTPException(status_code=404, detail="订阅不存在")
    return subscription

@app.delete("/api/subscriptions/{subscription_id}")
async def cancel_subscription(subscription_id: str, cancel_at_period_end: bool = True):
    """取消订阅"""
    subscription = subscription_service.cancel_subscription(subscription_id, cancel_at_period_end)
    if not subscription:
        raise HTTPException(status_code=404, detail="订阅不存在")
    return {"message": "订阅取消成功"}

@app.post("/api/subscriptions/{subscription_id}/upgrade", response_model=Dict[str, Any])
async def upgrade_subscription(subscription_id: str, request: SubscriptionUpgradeRequest):
    """升级/降级订阅（切换产品）"""
    subscription = subscription_service.upgrade_subscription(subscription_id, request)
    if not subscription:
        raise HTTPException(status_code=404, detail="订阅不存在")
    return subscription

# Customer Portal API
@app.post("/api/create-portal-session")
async def create_portal_session(request: CustomerPortalRequest):
    """创建 Customer Portal 会话"""
    try:
        # 验证客户是否存在
        customer = customer_service.get_customer(request.customer_id)
        if not customer:
            raise HTTPException(status_code=404, detail="客户不存在")
        
        # 创建 Customer Portal 会话
        session = stripe.billing_portal.Session.create(
            customer=customer['stripe_customer_id'],
            return_url=request.return_url
        )
        
        logger.info(f"Customer Portal 会话创建成功: {session.id} 客户: {request.customer_id}")
        
        return {
            "session_id": session.id,
            "url": session.url,
            "customer_id": request.customer_id
        }
        
    except stripe.error.StripeError as e:
        logger.error(f"Stripe错误: {str(e)}")
        raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
    except Exception as e:
        logger.error(f"创建 Portal 会话失败: {str(e)}")
        raise HTTPException(status_code=500, detail="创建 Portal 会话失败")

@app.get("/portal-return")
async def portal_return():
    """Customer Portal 返回页面"""
    return {
        "status": "success",
        "message": "订阅管理完成！",
        "timestamp": datetime.now().isoformat()
    }

@app.get("/subscription/success")
async def subscription_success(session_id: str):
    """订阅支付成功页面"""
    try:
        # 从Stripe获取会话详情
        session = stripe.checkout.Session.retrieve(session_id)
        
        # 如果会话完成，创建本地订阅记录
        if session.payment_status == 'paid' and session.subscription:
            # 从元数据中获取本地客户和产品ID
            customer_id = session.metadata.get('local_customer_id')
            product_id = session.metadata.get('local_product_id')
            
            if customer_id and product_id:
                # 检查是否已有订阅记录
                existing_subscription = None
                for sub_id, sub_data in subscription_service.subscriptions.items():
                    if (sub_data['customer_id'] == customer_id and 
                        sub_data['product_id'] == product_id):
                        existing_subscription = sub_data
                        break
                
                if existing_subscription:
                    # 如果已存在订阅记录，更新状态而不是创建新的
                    existing_subscription['stripe_subscription_id'] = session.subscription
                    existing_subscription['status'] = 'active'
                    existing_subscription['updated_at'] = datetime.now().isoformat()
                    existing_subscription['metadata'] = session.metadata
                    
                    DataStore.save_data(SUBSCRIPTIONS_FILE, subscription_service.subscriptions)
                    logger.info(f"订阅支付成功，更新现有记录: {existing_subscription['id']}")
                else:
                    # 创建新的本地订阅记录
                    local_subscription_id = str(uuid.uuid4())
                    subscription_data = {
                        'id': local_subscription_id,
                        'stripe_subscription_id': session.subscription,
                        'customer_id': customer_id,
                        'product_id': product_id,
                        'status': 'active',
                        # 'current_period_start': session.subscription_data.get('current_period_start'),
                        # 'current_period_end': session.subscription_data.get('current_period_end'),
                        'cancel_at_period_end': False,
                        'metadata': session.metadata,
                        'created_at': datetime.now().isoformat(),
                        'updated_at': datetime.now().isoformat()
                    }
                    
                    # 保存到本地存储
                    subscription_service.subscriptions[local_subscription_id] = subscription_data
                    DataStore.save_data(SUBSCRIPTIONS_FILE, subscription_service.subscriptions)
                    
                    logger.info(f"订阅支付成功，本地记录创建: {local_subscription_id}")
        
        return {
            "status": "success",
            "message": "订阅支付成功！",
            "session_id": session_id,
            "subscription_id": session.subscription,
            "timestamp": datetime.now().isoformat()
        }
        
    except stripe.error.StripeError as e:
        logger.error(f"获取会话信息失败: {str(e)}")
        return {
            "status": "error",
            "message": "获取支付信息失败",
            "session_id": session_id,
            "timestamp": datetime.now().isoformat()
        }

@app.get("/subscription/cancel")
async def subscription_cancel():
    """订阅支付取消页面"""
    return {
        "status": "cancelled",
        "message": "订阅支付已取消",
        "timestamp": datetime.now().isoformat()
    }

# 系统状态API
@app.get("/api/status")
async def get_system_status():
    """获取系统状态"""
    customers_count = len(customer_service.customers)
    products_count = len(product_service.products)
    subscriptions_count = len(subscription_service.subscriptions)
    
    return {
        "status": "running",
        "timestamp": datetime.now().isoformat(),
        "statistics": {
            "customers": customers_count,
            "products": products_count,
            "subscriptions": subscriptions_count
        },
        "data_files": {
            "customers": CUSTOMERS_FILE,
            "products": PRODUCTS_FILE,
            "subscriptions": SUBSCRIPTIONS_FILE
        }
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8003)
